﻿#include "stdafx.h"
#include "SqliteWrap.h"

#include "sqlite3.h"

#include <codecvt>

using namespace std;


namespace
{
    string toString(wstring ws)
    {
        std::wstring_convert<std::codecvt_utf8<wchar_t> > conv;
        return conv.to_bytes(ws);
    }

    wstring toWString(string s)
    {
        std::wstring_convert<std::codecvt_utf8<wchar_t> > conv;
        return conv.from_bytes(s);
    }

    class SqliteTest
    {
    public:
        SqliteTest()
        {
            SqliteWrap sqlite(L"D:\\材料库.db");

            std::vector<std::map<std::wstring, std::wstring>> table = sqlite.GetTableByName(L"钢管");
            std::string type = sqlite.GetColumnDataType(L"钢管", L"名称");
        }
    };
    SqliteTest s_sqliteTest;
}


SqliteWrap::SqliteWrap(const std::wstring& dbFilePath)
{
    sqlite3_open(toString(dbFilePath).c_str(), &m_pDb);
    if (m_pDb) // 设置多进程同时访问同一个数据库繁忙时等待超时时间。
        sqlite3_busy_timeout(m_pDb, 100);
}

SqliteWrap::~SqliteWrap()
{
    if (m_pDb)
    {
        sqlite3_close(m_pDb);
    }
}

std::vector<std::map<std::wstring, std::wstring>> SqliteWrap::GetTableBySql(const std::wstring& sql) const
{
    std::vector<std::map<std::wstring, std::wstring>> res;

    if (!m_pDb)
    {
        return res;
    }

    char** ppResults = nullptr;
    int row = 0;
    int column = 0;
    int ret = sqlite3_get_table(m_pDb, toString(sql).c_str(), &ppResults, &row, &column, nullptr);
    if (SQLITE_OK != ret || !ppResults)
    {
        if (ppResults)
        {
            sqlite3_free_table(ppResults);
        }

        return res;
    }

    for (int i = 1; i <= row; i++)
    {
        std::map<std::wstring, std::wstring> row;
        for (int j = 0; j < column; j++)
        {
            char* pValue = ppResults[i * column + j];
            if (pValue)
            {
                row.emplace(toWString(ppResults[j]), toWString(pValue));
            }
        }
        res.push_back(row);
    }

    if (ppResults)
    {
        sqlite3_free_table(ppResults);
    }

    return res;
}

std::vector<std::map<std::wstring, std::wstring>> SqliteWrap::GetTableByName(const std::wstring& tableName) const
{
    if (tableName.empty())
        return std::vector<std::map<std::wstring, std::wstring>>();

    std::wstring sql = L"select * from " + tableName;
    return GetTableBySql(sql);
}

std::string SqliteWrap::GetColumnDataType(const std::wstring& tableName, const std::wstring& columnName) const
{
    std::string res;

    if (!m_pDb)
    {
        return res;
    }

    const char* pDataType = nullptr;
    int ret = sqlite3_table_column_metadata(m_pDb, nullptr, toString(tableName).c_str(), toString(columnName).c_str(),
        &pDataType, nullptr, nullptr, nullptr, nullptr);
    if (pDataType)
    {
        res = pDataType;
    }

    return res;
}
